package com.medicalproject.controller;

import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import com.medical.pojo.AlipayUser;
import com.medicalproject.demo.AlipayConfig;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

@RestController
@RequestMapping("/api/alipay")
@Slf4j  // 使用Lombok简化日志
public class AlipayAuthController {

    @Autowired
    private AlipayClient alipayClient;

    @GetMapping("text")
    public String test() {
        return "text";
    }
    @GetMapping("/getAuthUrl")
    public String getAuthUrl() throws Exception {
        // 构建授权URL，添加更多权限scope
        String redirectUrl = URLEncoder.encode(AlipayConfig.return_url, StandardCharsets.UTF_8.name());
        String frontendUrl = URLEncoder.encode("http://localhost:8080/#/medical", StandardCharsets.UTF_8.name());

        // 添加更多权限scope
        String scope = "auth_user,auth_base";  // 添加基础权限和用户信息权限

        String authUrl = String.format("https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?" +
                        "app_id=%s&scope=%s&redirect_uri=%s&state=%s",
                AlipayConfig.app_id,
                scope,
                redirectUrl,
                frontendUrl);

        log.info("生成授权URL: {}", authUrl);
        return authUrl;
    }

    @GetMapping("/callback")
    public void callback(
            @RequestParam(value = "auth_code", required = false) String authCode,
            @RequestParam(value = "state", required = false) String state,
            HttpServletResponse response
    ) throws IOException {
        log.info("收到支付宝回调，auth_code: {}", authCode);

        try {
            if (authCode == null) {
                redirectWithError(response, state, "auth_code_empty", "授权码为空");
                return;
            }

            // 获取访问令牌
            AlipaySystemOauthTokenResponse tokenResponse = getAccessToken(authCode);
            if (tokenResponse == null || !tokenResponse.isSuccess()) {
                redirectWithError(response, state, "token_failed", "获取访问令牌失败");
                return;
            }

            // 获取用户信息
            AlipayUserInfoShareResponse userInfoResponse = getUserInfo(tokenResponse.getAccessToken());
            if (userInfoResponse == null || !userInfoResponse.isSuccess()) {
                redirectWithError(response, state, "userinfo_failed", "获取用户信息失败");
                return;
            }

            // 处理用户信息
            AlipayUser user = buildAlipayUser(userInfoResponse);
            logUserInfo(user);

            // 构建重定向URL
            String redirectUrl = buildRedirectUrl(state, user);
            response.sendRedirect(redirectUrl);

        } catch (Exception e) {
            log.error("处理支付宝回调失败", e);
            String errorMsg = e instanceof SocketTimeoutException ? "请求超时" : "系统异常";
            redirectWithError(response, state, "system_error", errorMsg);
        }
    }

    private AlipaySystemOauthTokenResponse getAccessToken(String authCode) throws Exception {
        int maxRetries = 3;
        int retryCount = 0;
        long retryDelay = 2000;

        while (retryCount < maxRetries) {
            try {
                AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
                request.setCode(authCode);
                request.setGrantType("authorization_code");

                log.info("尝试获取访问令牌，第{}次", retryCount + 1);
                AlipaySystemOauthTokenResponse response = alipayClient.execute(request);

                if (response.isSuccess()) {
                    log.info("获取访问令牌成功");
                    return response;
                }

                log.warn("获取访问令牌失败: {}", response.getMsg());
                retryCount++;
                if (retryCount < maxRetries) {
                    Thread.sleep(retryDelay);
                }
            } catch (Exception e) {
                log.error("获取访问令牌异常", e);
                retryCount++;
                if (retryCount >= maxRetries) throw e;
                Thread.sleep(retryDelay);
            }
        }
        return null;
    }

    private AlipayUserInfoShareResponse getUserInfo(String accessToken) throws Exception {
        int maxRetries = 3;
        int retryCount = 0;
        long retryDelay = 2000;

        while (retryCount < maxRetries) {
            try {
                AlipayUserInfoShareRequest request = new AlipayUserInfoShareRequest();
//                log.info("尝试获取用户信息，第{}次", retryCount + 1);
                AlipayUserInfoShareResponse response = alipayClient.execute(request, accessToken);

                if (response.isSuccess()) {
                    log.info("获取用户信息成功");
                    return response;
                }

                log.warn("获取用户信息失败: {}", response.getMsg());
                retryCount++;
                if (retryCount < maxRetries) {
                    Thread.sleep(retryDelay);
                }
            } catch (Exception e) {
                log.error("获取用户信息异常", e);
                retryCount++;
                if (retryCount >= maxRetries) throw e;
                Thread.sleep(retryDelay);
            }
        }
        return null;
    }

    private AlipayUser buildAlipayUser(AlipayUserInfoShareResponse response) {
        return AlipayUser.builder()
                .userId(response.getUserId())
                .nickName(response.getNickName())
                .avatar(response.getAvatar())
                .province(response.getProvince())
                .city(response.getCity())
                .gender(response.getGender())
                .isCertified(response.getIsCertified())
                .userType(response.getUserType())
                .userStatus(response.getUserStatus())
                .build();
    }

    private void logUserInfo(AlipayUser user) {
        log.info("用户信息: \n" +
                        "用户ID: {} \n" +
                        "昵称: {} \n" +
                        "头像: {} \n" +
                        "省份: {} \n" +
                        "城市: {} \n" +
                        "性别: {} \n" +
                        "是否认证: {} \n" +
                        "用户类型: {} \n" +
                        "用户状态: {}",
                user.getUserId(),
                user.getNickName(),
                user.getAvatar(),
                user.getProvince(),
                user.getCity(),
                user.getGender(),
                user.getIsCertified(),
                user.getUserType(),
                user.getUserStatus()
        );
    }

    private String buildRedirectUrl(String state, AlipayUser user) throws UnsupportedEncodingException {
        return state + String.format("?userId=%s&nickName=%s&avatar=%s",
                URLEncoder.encode(Optional.ofNullable(user.getUserId()).orElse(""), StandardCharsets.UTF_8.name()),
                URLEncoder.encode(Optional.ofNullable(user.getNickName()).orElse(""), StandardCharsets.UTF_8.name()),
                URLEncoder.encode(Optional.ofNullable(user.getAvatar()).orElse(""), StandardCharsets.UTF_8.name())
        );
    }

    private void redirectWithError(HttpServletResponse response, String state,
                                   String error, String message) throws IOException {
        String redirectUrl = state + "?error=" + error;
        if (message != null) {
            redirectUrl += "&message=" + URLEncoder.encode(message, StandardCharsets.UTF_8.name());
        }
        response.sendRedirect(redirectUrl);
    }
}